home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / unix / mp14tar.z / mp14tar / mpack / macbhex.c < prev    next >
C/C++ Source or Header  |  1994-06-01  |  9KB  |  308 lines

  1. /* macbhex.c -- simple binhex decoding routine
  2.  *
  3.  * (C) Copyright 1994 by Christopher J. Newman
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of Christopher J. Newman not be used in
  11.  * advertising or publicity pertaining to distribution of the software without
  12.  * specific, written prior permission.  Christopher J. Newman makes no
  13.  * representations about the suitability of this software for any purpose.  It
  14.  * is provided "as is" without express or implied warranty.
  15.  *
  16.  * CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  17.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
  18.  * SHALL CHRISTOPHER J. NEWMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  19.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  20.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  21.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  22.  * OF THIS SOFTWARE.
  23.  */
  24.  
  25. #include <stdio.h>
  26. #include <ctype.h>
  27. #include <memory.h>
  28. #include "macnapp.h"
  29. #include "macmpack.h"
  30.  
  31. /* from macos.c: */
  32. extern void renameDescFile(char *, short);
  33.  
  34. char binhex_decode[256] = {
  35.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  36.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  37.     -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, -1, -1,
  38.     13, 14, 15, 16, 17, 18, 19, -1, 20, 21, -1, -1, -1, -1, -1, -1,
  39.     22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1,
  40.     37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, -1, -1, -1, -1,
  41.     48, 49, 50, 51, 52, 53, 54, -1, 55, 56, 57, 58, 59, 60, -1, -1,
  42.     61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  43.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  44.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  45.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  46.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  47.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  48.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  49.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  50.     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  51. };
  52. #define BHEXVAL(c) (binhex_decode[(unsigned char) c])
  53.  
  54. typedef union {
  55.     unsigned char c[4];
  56.     unsigned long val;
  57. } longbuf;
  58.  
  59. typedef struct {
  60.     OSType type, creator;
  61.     unsigned short flags;
  62.     long dlen, rlen;
  63. } binhex_header;
  64.  
  65. #define STATE_START  0
  66. #define STATE_FNAME  1
  67. #define STATE_HEADER 2
  68. #define STATE_HCRC   3
  69. #define STATE_DFORK  4
  70. #define STATE_DCRC   5
  71. #define STATE_RFORK  6
  72. #define STATE_RCRC   7
  73. #define STATE_DONE   8
  74. #define STATE_ERROR  9
  75.  
  76. typedef struct binhex_state {
  77.     short state;            /* current state */
  78.     short part;                /* current part number */
  79.     unsigned short CRC;        /* cumulative CRC */
  80.     unsigned short fileCRC;    /* CRC value from file */
  81.     longbuf octetbuf;        /* buffer for decoded 6-bit values */
  82.     short octetin;            /* current input position in octetbuf */
  83.     short donepos;            /* ending position in octetbuf */
  84.     short inCRC;            /* flag set when reading a CRC */
  85.     long count;                /* generic counter */
  86.     FILE *outfile;            /* output file */
  87.     short marker;            /* flag indicating maker */
  88.     unsigned char rlebuf;    /* buffer for last run length encoding value */
  89.     PCstr namebuf[65];        /* buffer for binhex filename */
  90.     binhex_header head;        /* buffer for header */
  91.     SFReply reply;            /* buffer for user output filename */
  92. } binhex_state;
  93.  
  94. /* global state */
  95. static binhex_state bh;
  96.  
  97. /* process a binhex character
  98.  */
  99. void binhex_process(FILE *infile)
  100. {
  101.     unsigned short tmpcrc, cval;
  102.     unsigned char ctmp, c = bh.rlebuf;
  103.     Point where;
  104.     FInfo finfo;
  105.     char buf[256];
  106.     extern Cursor watch;
  107.     
  108.     /* do CRC */
  109.     ctmp = bh.inCRC ? c : 0;
  110.     cval = bh.CRC & 0xf000;
  111.     tmpcrc = ((unsigned short) (bh.CRC << 4) | (ctmp >> 4))
  112.             ^ (cval | (cval >> 7) | (cval >> 12));
  113.     cval = tmpcrc & 0xf000;
  114.     bh.CRC = ((unsigned short) (tmpcrc << 4) | (ctmp & 0x0f))
  115.             ^ (cval | (cval >> 7) | (cval >> 12));
  116.  
  117.     /* handle state */
  118.     switch (bh.state) {
  119.         case STATE_START:
  120.             bh.state = STATE_FNAME;
  121.             bh.count = 1;
  122.             *bh.namebuf = (c & 63);
  123.             break;
  124.         case STATE_FNAME:
  125.             bh.namebuf[bh.count] = c;
  126.             if (bh.count++ > *bh.namebuf) {
  127.                 bh.state = STATE_HEADER;
  128.                 bh.count = 0;
  129.             }
  130.             break;
  131.         case STATE_HEADER:
  132.             ((char *)&bh.head)[bh.count] = c;
  133.             if (++bh.count == 18) {
  134.                 bh.state = STATE_HCRC;
  135.                 bh.inCRC = 1;
  136.                 bh.count = 0;
  137.             }
  138.             break;
  139.         case STATE_DFORK:
  140.         case STATE_RFORK:
  141.             putc(c, bh.outfile);
  142.             if (--bh.count == 0) {
  143.                 fclose(bh.outfile);
  144.                 bh.outfile = NULL;
  145.                 ++bh.state;
  146.                 bh.inCRC = 1;
  147.             }
  148.             break;
  149.         case STATE_HCRC:
  150.         case STATE_DCRC:
  151.         case STATE_RCRC:
  152.             if (!bh.count++) {
  153.                 bh.fileCRC = (unsigned short) c << 8;
  154.             } else {
  155.                 if ((bh.fileCRC | c) != bh.CRC) {
  156.                     if (bh.state > STATE_HCRC) {
  157.                         FSDelete(bh.reply.fName, bh.reply.vRefNum);
  158.                         SetCursor(&arrow);
  159.                         yell("BinHex file corrupted in transit");
  160.                         SetCursor(&watch);
  161.                     }
  162.                     bh.state = STATE_ERROR;
  163.                     break;
  164.                 }
  165.                 bh.CRC = 0;
  166.                 if (++bh.state == STATE_DONE) {
  167.                     finfo.fdType = bh.head.type;
  168.                     finfo.fdCreator = bh.head.creator;
  169.                     finfo.fdFlags = bh.head.flags & 0xf800;
  170.                     SetFInfo(bh.reply.fName, bh.reply.vRefNum, &finfo);
  171.                     PtoCstr(bh.reply.fName);
  172.                     renameDescFile((char *)bh.reply.fName, bh.reply.vRefNum);
  173.                     break;
  174.                 }
  175.                 bh.count = bh.head.rlen;
  176.                 if (bh.state == STATE_DFORK) {
  177.                     /* prompt user */
  178.                     sprintf(buf, "Saving BinHex file %s", C(bh.namebuf));
  179.                     chat(buf);
  180.                     where.h = where.v = 0;
  181.                     SetCursor(&arrow);
  182.                     SFPutFile(where, "\pSave decoded BinHex file as:", P(bh.namebuf),
  183.                         NULL, &bh.reply);
  184.                     SetCursor(&watch);
  185.                     if (!bh.reply.good) {
  186.                         bh.state = STATE_ERROR;
  187.                     } else {
  188.                         Create(bh.reply.fName, bh.reply.vRefNum,
  189.                             bh.head.creator, bh.head.type);
  190.                         bh.count = bh.head.dlen;
  191.                     }
  192.                 }
  193.                 if (bh.count) {
  194.                     bh.inCRC = 0;
  195.                     bh.outfile = Macopen(infile, bh.reply.fName, bh.reply.vRefNum,
  196.                         0, 1, bh.state == STATE_DFORK ? 0 : 1, fsWrPerm);
  197.                     if (!bh.outfile) {
  198.                         bh.state = STATE_ERROR;
  199.                         FSDelete(bh.reply.fName, bh.reply.vRefNum);
  200.                         SetCursor(&arrow);
  201.                         yell("Failed to open file for writing");
  202.                         SetCursor(&watch);
  203.                     }
  204.                 } else {
  205.                     ++bh.state;
  206.                 }
  207.             }
  208.             break;
  209.     }
  210. }
  211.  
  212. /*
  213.  * decode a binhex file
  214.  *  returns -1 on fatal error, 0 for continue, 1 for done
  215.  */
  216. int os_binhex(FILE *infile, int part, int nparts)
  217. {
  218.     long val;
  219.     int c;
  220.     char *bptr;
  221.     short octetpos;
  222.     static char buf[1024];
  223.     
  224.     /* reset state */
  225.     if (part == 1) {
  226.         bh.state = STATE_START;
  227.         bh.part = 0;
  228.         bh.CRC = 0;
  229.         bh.octetbuf.val = 0;
  230.         bh.octetin = 26;
  231.         bh.donepos = 3;
  232.         bh.inCRC = 0;
  233.         bh.outfile = NULL;
  234.         bh.marker = 0;
  235.     }
  236.     if (++bh.part != part) bh.state = STATE_ERROR;
  237.     
  238.     /* do nothing on error/completion */
  239.     if (!infile) {
  240.         if (bh.state < STATE_DONE) bh.state = STATE_ERROR;
  241.     } else {
  242.         /* skip blank lines */
  243.         do {
  244.             if (fgets(buf, sizeof (buf), infile) == NULL) return (0);
  245.         } while (*buf == '\n');
  246.         bptr = buf;
  247.         if (part == 1 && *bptr++ != ':') bh.state = STATE_ERROR;
  248.         
  249.         /* line reading loop */
  250.         do {
  251.             /* check line for separator */
  252.             if (!strncmp(buf, "--- ", 4)) break;
  253.             buf[strlen(buf) - 1] = '\0';
  254.             
  255.             /* loop through line of binhex charaters */
  256.             while (bh.state < STATE_DONE) {
  257.                 /* fill in octetbuf */
  258.                 do {
  259.                     if ((val = BHEXVAL(*bptr++)) == -1) {
  260.                         if (bptr[-1]) {
  261.                             --bh.donepos;
  262.                             if (bh.octetin >= 14) --bh.donepos;
  263.                             if (bh.octetin >= 20) --bh.donepos;
  264.                         }
  265.                         break;
  266.                     }
  267.                     bh.octetbuf.val |= val << bh.octetin;
  268.                 } while ((bh.octetin -= 6) > 2);
  269.                 if (!bptr[-1]) break;
  270.                 
  271.                 /* handle decoded characters -- run length encoding (rle) detection */
  272.                 for (octetpos = 0; octetpos < bh.donepos; ++octetpos) {
  273.                     /* get character & handle rle */
  274.                     c = bh.octetbuf.c[octetpos];
  275.                     if (c == 0x90 && !bh.marker++) continue;
  276.                     if (bh.marker) {
  277.                         if (c == 0) {
  278.                             bh.rlebuf = 0x90;
  279.                             binhex_process(infile);
  280.                         } else {
  281.                             while (--c > 0) {
  282.                                 binhex_process(infile);
  283.                             }
  284.                         }
  285.                         bh.marker = 0;
  286.                     } else {
  287.                         bh.rlebuf = (unsigned char) c;
  288.                         binhex_process(infile);
  289.                     }
  290.                     if (bh.state >= STATE_DONE) break;
  291.                 }
  292.                 if (bh.donepos < 3 && bh.state < STATE_DONE) bh.state = STATE_ERROR;
  293.                 bh.octetin = 26;
  294.                 bh.octetbuf.val = 0;
  295.             }
  296.         } while (bh.state < STATE_DONE && fgets(bptr = buf, sizeof (buf), infile) != NULL);
  297.     }
  298.     
  299.     /* error clean up */
  300.     if (bh.state == STATE_ERROR && bh.outfile) {
  301.         fclose(bh.outfile);
  302.         bh.outfile = NULL;
  303.         FSDelete(bh.reply.fName, bh.reply.vRefNum);
  304.     }
  305.     
  306.     return (bh.state == STATE_ERROR ? 1 : 0);
  307. }
  308.